define('common:widget/ui/ai/imageEdit/index', function(require, exports, module) {

  var $ = require('common:widget/ui/base/base');
  var events = require('common:widget/ui/base/events');
  /* eslint-disable no-undef */
  /**
   * 图片编辑
   * @param {element} root 画布挂载跟节点
   * @param {object} options
   * @param {string} options.imageSrc 编辑的图片
   * @param {number} options.imageWidth 编辑的图片宽
   * @param {number} options.imageHeight 编辑的图片高
   * @param {number = 50} options.brushWidth 笔刷宽度
   * @param {string = rgb(235, 51, 51)} options.brushColor 笔刷颜色
   * @param {number = 0.25} options.minZoom 画布最小缩放值
   * @param {number = 2} options.maxZoom 画布最大缩放值
   * @constructor
   */
  function ImageEdit(root, options) {
      this.$root = $(root);
      this.brushWidth = options.brushWidth || 50;
      this.brushColor = options.brushColor || 'rgb(235, 51, 51)';
      this.imageSrc = options.imageSrc;
      this.imageWidth = options.imageWidth;
      this.imageHeight = options.imageHeight;
      this.minZoom = options.minZoom || 0.25;
      this.maxZoom = options.maxZoom || 2;
  
       /**
       * 鼠标状态：
       *    MOVE : 移动模式
       *    BRUSH ：画笔模式
       */
      this.canvasMode = null;
      // 容器尺寸
      this.innerWidth = this.$root.innerWidth();
      this.innerHeight = this.$root.innerHeight();
      // 画布放大倍数
      this.canvasScale = 1;
      this.isMouseDown = false;
      this.lastMouseX = 0;
      this.lastMouseY = 0;
      // 是否支持滚轮缩放
      this.isWheelZoom = true;
      // 画布偏移量
      this.canvasWrapLeft = 0;
      this.canvasWrapTop = 0;
      // 画布初始化展示的宽高，且用来初始化canvas的width、height，后续用来计算画布放大和缩小
      this.originWidth = 0;
      this.originHeight = 0;
      // 是否涂抹
      this.isPaint = false;
      // 涂抹痕迹历史栈
      this.strokeHistory = [];
      this.strokeHistoryIndex = -1;
      this._renderEditDom();
  }
  $.extend(ImageEdit.prototype, events, {
      // 初始化创建画布相关dom
      _renderEditDom: function () {
          var layout = this._getCanvasLayoutInfo();
          // 创建画布相关dom
          /* eslint-disable  max-len */
          var template = ''
              + '<div class="container" style="position: relative; width: 100%; height: 100%;overflow: hidden;">'
              + '     <div'
              + '         class="canvas-wrap"'
              + '         style="overflow: hidden; width: ' + layout.width + 'px; height: ' + layout.height + 'px; position: absolute; top: '
                          + layout.top + 'px;left: ' + layout.left + 'px;background-image: url(' + this.imageSrc + '); background-repeat: no-repeat; background-size: 100% 100%;">'
              + '         <canvas'
              + '             id="mainCanvas"'
              + '              style="opacity: 0.45; width: 100%; height: 100%;" width="' + layout.width + '" height="' + layout.height + '">'
              + '         </canvas>'
              + '            <div'
              + '                class="draw-pen"'
              + '                style="position: absolute;display: none; transform: translate(-50%, -50%);border: 2px solid #fff;'
              + '                pointer-events: none; border-radius: 50%;background-color: rgba(255,255,255,.4)"'
              + '            ></div>'
              + '     </div>'
              + '</div>';
          /* eslint-enable  max-len */
          this.$container = $(template);
  
          this.$mainCanvas = this.$container.find('#mainCanvas');
          this.$canvasWrap = this.$container.find('.canvas-wrap');
          this.$drawPen = this.$container.find('.draw-pen');
          this.$root.html(this.$container);
          this._initCanvasCtx();
          this._bindEvents();
      },
      // 初始化canvas上下文信息
      _initCanvasCtx: function () {
          var mainCanvasEle = this.$mainCanvas[0];
          var mainCanvasCtx = this.mainCanvasCtx = this.mainCanvasCtx || mainCanvasEle.getContext('2d');
          mainCanvasEle.width = this.originWidth;
          mainCanvasEle.height = this.originHeight;
          mainCanvasCtx.clearRect(0, 0, this.originWidth, this.originHeight);
          mainCanvasCtx.lineCap = 'round';
          mainCanvasCtx.fillStyle = this.brushColor;
          mainCanvasCtx.strokeStyle = this.brushColor;
          this.setBrushWidth(this.brushWidth);
      },
      // 获取canvas布局相关信息宽、高、在根容器的位置
      _getCanvasLayoutInfo: function () {
          var imgRatio = this.imageWidth / this.imageHeight;
          var ratio = this.innerWidth / this.innerHeight;
          var width = 0;
          var height = 0;
          if (ratio > imgRatio) {
              width = this.innerHeight * imgRatio;
              height = this.innerHeight;
          } else {
              height = this.innerWidth / imgRatio;
              width = this.innerWidth;
          }
          this.originWidth = width;
          this.originHeight = height;
          var curWidth = width * this.canvasScale;
          var curHeight = height * this.canvasScale;
          this.canvasWrapTop = (this.innerHeight - curHeight) / 2;
          this.canvasWrapLeft = (this.innerWidth - curWidth) / 2;
          return {
              width: curWidth,
              height: curHeight,
              top: this.canvasWrapTop,
              left: this.canvasWrapLeft
          };
      },
      _bindEvents: function () {
          this.handleOnwheel = this._handleOnwheel.bind(this);
          this.handleMouseDown = this._handleMouseDown.bind(this);
          this.handleMouseMove = this._handleMouseMove.bind(this);
          this.handleMouseUp = this._handleMouseUp.bind(this);
          this.handleMouseEnter = this._handleMouseEnter.bind(this);
          this.handleMouseOut = this._handleMouseOut.bind(this);
          this.handleContextmenu = this._handleContextmenu.bind(this);
          this.$canvasWrap.on('mousewheel', this.handleOnwheel);
          this.$canvasWrap.on('mousedown', this.handleMouseDown);
          this.$canvasWrap.on('mouseenter', this.handleMouseEnter);
          this.$canvasWrap.on('mouseout', this.handleMouseOut);
          this.$canvasWrap.on('contextmenu', this.handleContextmenu);
          $(document).on('mousemove', this.handleMouseMove);
          $(document).on('mouseup', this.handleMouseUp);
      },
      _unbindEvents: function () {
          this.$canvasWrap.off('mousewheel', this.handleOnwheel);
          this.$canvasWrap.off('mousedown', this.handleMouseDown);
          this.$canvasWrap.off('mouseenter', this.handleMouseEnter);
          this.$canvasWrap.off('mouseout', this.handleMouseOut);
          this.$canvasWrap.off('contextmenu', this.handleContextmenu);
          $(document).off('mousemove', this.handleMouseMove);
          $(document).off('mouseup', this.handleMouseUp);
      },
      // 控制鼠标缩放
      _handleOnwheel: function (event) {
          if (!this.isWheelZoom) {
              return;
          }
          var e = event.originalEvent || event;
          e.stopPropagation();
          e.preventDefault();
          var wheelDelta = e.wheelDelta || e.detail * -1;
          var newScale = this.canvasScale + 0.1 * (wheelDelta > 0 ? 1 : -1);
          this.zoom(newScale, {
              clientX: e.clientX,
              clientY: e.clientY
          });
          this.$drawPen.css({
              left: e.offsetX,
              top: e.offsetY
          });
      },
      _handleMouseDown: function (event) {
          event.stopPropagation();
          event.preventDefault();
          // 获取当前鼠标坐标
          var downX = event.clientX;
          var downY = event.clientY;
  
          // 根据鼠标状态判断执行什么方法
          switch (this.canvasMode) {
          case 'MOVE':
              this._handleMoveMode(downX, downY);
              break;
          case 'BRUSH':
              this.isMouseDown = true;
              var layout = this.$canvasWrap[0].getBoundingClientRect();
              this.lastMouseX = event.clientX - layout.left;
              this.lastMouseY = event.clientY - layout.top;
              this._handlePaint({
                  startX: this.lastMouseX,
                  startY: this.lastMouseY
              }, {
                  endX: this.lastMouseX + 0.1,
                  endY: this.lastMouseY + 0.1
              });
              break;
          default:
              break;
          }
  
      },
      // 控住画布拖拽
      _handleMoveMode: function (downX, downY) {
          // 获取上次移动完成的偏移量
          var container = this.$container[0];
          var top = this.canvasWrapTop;
          var left = this.canvasWrapLeft;
          var _this = this;
          document.onmousemove = function (event) {
              event.stopPropagation();
              event.preventDefault();
              var moveX = event.clientX;
              var moveY = event.clientY;
              _this.$canvasWrap.css({
                  left: _this.canvasWrapLeft = left + (moveX - downX),
                  top: _this.canvasWrapTop = top + (moveY - downY)
              });
  
          };
  
          container.onmouseout = document.onmouseup = function (event) {
              event.stopPropagation();
              event.preventDefault();
  
              document.onmousemove = null;
              container.onmouseout = document.onmouseup = null;
          };
      },
      _handleMouseMove: function (event) {
          if (this.canvasMode !== 'BRUSH') {
              return;
          }
          var layout = this.$canvasWrap[0].getBoundingClientRect();
          var newX = event.clientX - layout.left;
          var newY = event.clientY - layout.top;
          // 画笔移动
          this.$drawPen.css({
              left: newX,
              top: newY
          });
          if (this.isMouseDown) {
              this.isPaint = true;
              this._handlePaint({
                  startX: this.lastMouseX,
                  startY: this.lastMouseY
              }, {
                  endX: newX,
                  endY: newY
              });
  
              this.lastMouseX = newX;
              this.lastMouseY = newY;
          }
      },
      _handlePaint: function (start, end) {
          this.isPaint = true;
          var ctx = this.mainCanvasCtx;
          var dpr = 1 / this.canvasScale;
          ctx.beginPath();
          ctx.moveTo(start.startX * dpr, start.startY * dpr);
          ctx.lineTo(end.endX * dpr, end.endY * dpr);
          ctx.stroke();
      },
      _handleMouseUp: function (event) {
          var target = event.target;
          if (this.canvasMode === 'BRUSH' && this.isMouseDown) {
              this.dispatchEvent('brushEnd');
              this.saveState();
              if (target.id !== 'mainCanvas' && target.tagName !== 'CANVAS') {
                  this.$drawPen.hide();
              }
          }
          this.isMouseDown = false;
      },
      _handleMouseEnter: function (event) {
          this.dispatchEvent('hideReplaceGuide');
          switch (this.canvasMode) {
              case 'MOVE':
                  this.$mainCanvas.css({cursor: 'grab'});
                  this.$drawPen.hide();
                  break;
              case 'BRUSH':
                  this.$mainCanvas.css({cursor: 'none'});
                  this.$drawPen.css({
                      display: 'block',
                      width: this.brushWidth,
                      height: this.brushWidth,
                      left: event.offsetX,
                      top: event.offsetY
                  });
                  break;
              default:
                  this.$mainCanvas.css({cursor: 'auto'});
                  this.$drawPen.hide();
                  break;
          }
      },
      _handleMouseOut: function () {
          if (this.isMouseDown) {
              return;
          }
          this.$drawPen.hide();
      },
  
      _handleContextmenu: function (event) {
  
          // 图片区域禁用鼠标右键，防止未登录保存
          event.preventDefault();
      },
      zoom: function (scale, center) {
          if (typeof scale !== 'number') {
              return;
          }
          scale = Math.max(this.minZoom, Math.min(this.maxZoom, scale));
          if (scale === this.canvasScale) {
              return;
          }
          this.canvasScale = scale;
          var canvasWrapEle = this.$canvasWrap[0];
          var rect = canvasWrapEle.getBoundingClientRect();
          var left = rect.left;
          var top = rect.top;
          var curWidth = rect.width;
          var curHeight = rect.height;
          // 手动缩放时，设置缩放中心点为元素的中心点；鼠标滚轮缩放时，缩放中心点为鼠标当前坐标
          center = center || {
              clientX: left + curWidth / 2,
              clientY: top + curHeight / 2
          };
  
          var scaleWidth = this.originWidth * scale;
          var scaleHeight = this.originHeight * scale;
          // 由于放大或缩小时，元素会偏移，因此通过每次宽或高放大的比例 对left和top进行纠正
          var newLeft = this.canvasWrapLeft - (center.clientX - left) * (Math.round(scaleWidth) - curWidth) / curWidth;
          var newTop = this.canvasWrapTop - (center.clientY - top) * (Math.round(scaleHeight) - curHeight) / curHeight;
          this.canvasWrapLeft = newLeft;
          this.canvasWrapTop = newTop;
          this.$canvasWrap.css({
              width: scaleWidth,
              height: scaleHeight,
              left: newLeft,
              top: newTop
          });
          this.mainCanvasCtx.lineWidth = this.brushWidth / this.canvasScale;
          this.dispatchEvent('scaleChanged', {scale: Math.round(this.canvasScale * 1000) / 1000});
      },
  
      move: function (flag) {
          this.canvasMode = flag ? 'MOVE' : null;
          this.$drawPen.hide();
      },
      brush: function (flag) {
          this.canvasMode = flag ? 'BRUSH' : null;
      },
      // 设置笔刷宽度
      setBrushWidth: function (width) {
          if (!width || !this.mainCanvasCtx) {
              return;
          }
          this.mainCanvasCtx.lineWidth = width / this.canvasScale;
          this.brushWidth = width;
      },
      clearCanvas: function () {
          if (!this.mainCanvasCtx) {
              return;
          }
          this.isPaint = false;
          this.mainCanvasCtx.clearRect(0, 0, this.originWidth, this.originHeight);
          this.strokeHistory = [];
          this.strokeHistoryIndex = -1;
      },
      // 更新图片信息
      updateImage: function (params) {
          if (!params.src || !params.width || !params.height) {
              return;
          }
          this.imageSrc = params.src;
          this.imageWidth = params.width;
          this.imageHeight = params.height;
          this.canvasMode = null;
          this.canvasScale = 1;
          var layout = this._getCanvasLayoutInfo();
          this.$canvasWrap.css($.extend(layout, {
              backgroundImage: 'url(' + this.imageSrc + ')'
          }));
          this.clearCanvas();
          this._initCanvasCtx();
          this.dispatchEvent('scaleChanged', {scale: this.canvasScale});
      },
      reset: function () {
          this.canvasMode = null;
          this.canvasScale = 1;
          this.isWheelZoom = false;
          this.resize();
          this.clearCanvas();
          this._initCanvasCtx();
          this.dispatchEvent('scaleChanged', {scale: this.canvasScale});
          this.$drawPen.hide();
      },
      resize: function () {
          this.innerWidth = this.$root.innerWidth();
          this.innerHeight = this.$root.innerHeight();
          var oldWidth = this.originWidth;
          var layout = this._getCanvasLayoutInfo();
          this.$canvasWrap.css(layout);
          this.mainCanvasCtx.scale(oldWidth / this.originWidth, oldWidth / this.originWidth);
      },
      destroy: function () {
          this._unbindEvents();
          this.$root.remove();
          this.$mainCanvas = null;
          this.$canvasWrap = null;
          this.$drawPen = null;
          this.$root = null;
          this.mainCanvasCtx = null;
      },
      allowWhellZoom: function (flag) {
          this.isWheelZoom = !!flag;
      },
  
      /**
       * 出现笔触操作后，保存涂抹痕迹历史栈，并通知外部
       */
      saveState: function () {
          this.strokeHistory.push(this.mainCanvasCtx.getImageData(0, 0, this.originWidth, this.originHeight));
          this.strokeHistoryIndex++;
          this.dispatchEvent('strokeHistoryChange', {
              strokeHistory: this.strokeHistory,
              strokeHistoryIndex: this.strokeHistoryIndex
          });
  
      },
  
      /**
       * 外部可能会会出现抛弃后续笔触历史的操作，这时接收并更新，以保持同步
       */
      updateStrokeHistory: function (params) {
          this.strokeHistory = params.strokeHistory;
          this.strokeHistoryIndex = params.strokeHistoryIndex;
      },
      redrawCanvas: function (strokeImageData) {
          if (!strokeImageData) {
              this.mainCanvasCtx.clearRect(0, 0, this.originWidth, this.originHeight);
              return;
          }
          this.mainCanvasCtx.putImageData(strokeImageData, 0, 0);
      },
  
      /**
       * 画布图片展示的 data URI
       * @returns base64 || ''
       */
      getCanvasDataURL: function () {
          if (!this.isPaint) {
              return '';
          }
          var resultCanvas = document.createElement('canvas');
          var resultCtx = resultCanvas.getContext('2d');
          var imageWidth = this.imageWidth;
          var imageHeight = this.imageHeight;
          resultCanvas.width = imageWidth;
          resultCanvas.height = imageHeight;
  
          resultCtx.fillStyle = '#000';
          resultCtx.fillRect(0, 0, imageWidth, imageHeight);
          // 将 main 作为 image 的 mask
          resultCtx.drawImage(this.$mainCanvas[0], 0, 0, imageWidth, imageHeight);
  
          var maskedData = resultCtx.getImageData(0, 0, imageWidth, imageHeight);
          var maskedPixels = maskedData.data;
          for (let i = 0; i < maskedPixels.length; i += 4) {
              if (maskedPixels[i] > 0) {
                  // 如果 main 的红色通道有值，说明是绘图区域， 将mask转为涂抹区为白色，背景为黑色的图
                  maskedPixels[i] = 255;
                  maskedPixels[i + 1] = 255;
                  maskedPixels[i + 2] = 255;
                  maskedPixels[i + 3] = 255;
              }
          }
          resultCtx.putImageData(maskedData, 0, 0);
          return resultCanvas.toDataURL('image/jpeg', 1);
      },
      /**
       *
       * @param {string} src 图片链接
       * @param {number} w 图片宽
       * @param {number} h 图片高
       * @param {object} options 配置
       * @param {string = 'jpeg'} options.type 图片格式
       * @param {number = 1} options.quality 图片质量
       * @returns {Promise<base64>}
       */
      getBase64Image: function (src, w, h, options) {
          options = $.extend({
              type: 'jpeg',
              quality: 1
          }, options || {});
          var pro = new $.Deferred();
          if (src.indexOf('data:image') >= 0) {
              pro.resolve(src);
          } else {
              var resultCanvas = document.createElement('canvas');
              var resultCtx = resultCanvas.getContext('2d');
              resultCanvas.width = w;
              resultCanvas.height = h;
              var image = new Image();
              image.crossOrigin = 'anonymous';
              image.onload = function () {
                  resultCtx.drawImage(image, 0, 0, w, h);
                  pro.resolve(resultCanvas.toDataURL('image/' + options.type, options.quality));
              };
              image.onerror = function () {
                  pro.resolve('');
              };
              image.src = src;
          }
          return pro;
      }
  });
  
  return ImageEdit;
  

});
